package com.smh.demo1.a36;

import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.ClassUtils;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;

/**
 * @author shiminghui
 * @date 2025/5/9 18:53
 * @description: TODO
 */
public class A36 {
    public static void main(String[] args) {

        // 其实条件注解的底层实现就是判断,功能专一的注解如@ConditionalOnBean,就是组合了Condition注解,然后加入特定的逻辑

        GenericApplicationContext context = new GenericApplicationContext();
        // 注册一些常用的BeanFactory和Bean后处理器
        AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
        context.registerBean("config", Config.class);
        context.refresh();

        // 打印BeanDefinition
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }

    }


    @Target({ElementType.METHOD, ElementType.TYPE}) // 注解的作用目标, 方法或者类
    @Retention(RetentionPolicy.RUNTIME) // 注解的保留策略
    @Conditional(IsExitsClass.class)
    @interface ConditionOnClass {
        boolean exist() default true;

        Class clazz();
    }

    // 匹配逻辑
    static class IsExitsClass implements Condition {
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
            boolean exist = (boolean) attributes.get("exist");
            Class o = (Class) attributes.get("clazz");
            boolean present = ClassUtils.isPresent(o.getName(), null);
            return exist == present;
        }
    }


    @Configuration
    static class Config {

        @Bean
        @ConditionOnClass(clazz = Bean3.class)
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        @ConditionOnClass(clazz = Bean3.class, exist = false)
        public Bean2 bean2() {
            return new Bean2();
        }

    }

    static class Bean1 {

    }

    static class Bean2 {

    }

    static class Bean3 {

    }
}
